-- TD4.7.2 Try.SNK DRP Connect DRP Test

-- Timing Conditions 配置
param_conditions = {
    {50, 0.3}, {75, 0.3}, {100, 0.3},
    {50, 0.5}, {75, 0.5}, {100, 0.5},
    {50, 0.7}, {75, 0.7}, {100, 0.7}
}

-- Hex 打印函数
local function to_hex(str)
    local parts = {}
    for i = 1, #str do
        parts[i] = string.format("0x%02X", str:byte(i))
    end
    return table.concat(parts, " ")
end

-- 初始化部分
baselib.report(0x00, "TD4.7.2 beginning.") 
busilib.ResetOutputs()  -- 恢复到脚本执行前的初始状态
-- 过压保护
busilib.SetProtecter(ADC.VBUS, 3900, 8, 0x40021018, 0x0100, 0)      -- 6V SW.VBUS_GEN GPIOE.8
busilib.SetProtecter(ADC.CC1, 12000, 8, 0x40020418, 0x4000, 0)      -- 5.5V SW.VCONN_GEN GPIOB.14
busilib.SetProtecter(ADC.CC2, 12000, 8, 0x40020418, 0x4000, 0)      -- 5.5V SW.VCONN_GEN GPIOB.14
busilib.setUsbCable(1, 1)  -- 第二个参数设置为1表示测试仪需要模拟电缆
tcpclib.Reinit(1, 0)       -- 重新初始化 TCPC
-- 设备启动时默认状态就是Disable.SRC
busilib.setUsbCcs(1, CCS.Disabled)            
busilib.setUsbRole(1, ROLE.Source)  

for i, condition in ipairs(param_conditions) do
    local tDRP = condition[1]
    local dcSRC = condition[2]
    -- 第一步: CVS 应用其中一组 Timing Condition
    baselib.report(0x00, "CVS Applying Condition: tDRP = ".. tDRP ..", dcSRC.DRP = ".. dcSRC ..".")

    -- 第二步: For a PUT_R, one CC is terminated with Ra for the test
    if Captive_Cable then
        busilib.SetSwitchState(SW.CC2_RA, 1)    -- 在CC2加载Ra
        baselib.report(0x00, "检测到 PUT 为 PUT_R, CC2 terminated with Ra.")
    end
 
    local attempt_count = 0    -- 初始化尝试次数
    -- 这里是步骤4.c: If the PUT has reached this step less than 5 times since step 1, transition to step 3. 若PUT进入此步骤未满5次，则跳回步骤3
    while attempt_count < 5 do  
        -- 第三步: CVS transitions to Unattached.SNK for (tDRP - dcSRC.DRP x tDRP)
        local hold_time = math.floor(tDRP - (tDRP * dcSRC))  -- 计算维持时间
        busilib.setUsbCcs(1, CCS.Unattached)  
        busilib.setUsbRole(1, ROLE.Sink)  
        baselib.delay(hold_time) 
        baselib.report(0x00, "CVS 转换到 Unattached.SNK 状态, 维持时间: " .. hold_time .. "ms.")
        -- 第3.a步: CVS monitors CCs for Rp 监控两个CC引脚是否出现Rp（电压 > 0.25V）and transitions to AttachedWait.SNK if it is detected 若检测到Rp，转换到AttachedWait.SNK
        -- 注: 测试仪默认使用CC1, 所以只监控CC1即可
        local VCC1 = busilib.GetADC(ADC.CC1, 4)
        if VCC1 > 250 then
            busilib.setUsbCcs(1, CCS.AttachWait)
            baselib.report(0x00, "检测到 CC 引脚的 Rp.CVS 转换到 AttachedWait.SNK.")
        end
        -- 第3.b步: If Rp is present for tDRP 如果Rp存在并维持tDRP时间
        local cc1_rp_maintained = busilib.waitCondition4ad(ADC.CC1, 4, 250, 5000, 5, tDRP)  -- 连续5次检测到CC1的电压大于0.25v
        if cc1_rp_maintained == LuaOk then  -- Rp在tDRP时间内持续存在，执行后续操作
            -- 3.b.i: CVS verifies that PUT attaches Rds after tCCDebounce  验证PUT在tCCDebounce后是否应用Rds [TD.4.7.2.V.1]
            baselib.delay(200)  -- tCCDebounce = 100ms - 200ms
            VCC1 = busilib.GetADC(ADC.CC1, 4)
            baselib.report(0x00, "测量得到的 CC1 电压为 " .. VCC1 .. ".") 
            if VCC1 < 150 then 
                baselib.report(0x00, "TD.4.7.2.V.1 pass.")
            else
                baselib.report(0x00, "TD.4.7.2.V.1 fail.")
                baselib.report(0x00, "没有检测到 CC 引脚的 Rd.PUT 可能已经转换到 Attached.SRC.")
                goto Script_END -- PUT 如果已经转换到 Attached.SRC, 应该直接结束脚本
            end
            -- 3.b.ii: CVS transitions through Unattached.SRC and AttachWait.SRC to Attached.SRC 
            busilib.setUsbCcs(1, CCS.Unattached)
            busilib.setUsbRole(1, ROLE.Source)    -- 过渡到Unattached.SRC
            baselib.report(0x00, "CVS 转换到 Unattached.SRC 状态")
            baselib.delay(5)
            busilib.setUsbCcs(1, CCS.AttachWait)  -- 过渡到AttachWait.SRC
            baselib.report(0x00, "CVS 转换到 AttachWait.SRC 状态")
            baselib.delay(5)
            busilib.preparePower(1, 1, 5000)      -- 准备 VBus 电压
            busilib.preparePower(1, 0, 3300)      -- 准备 VConn 电压
            busilib.setUsbCcs(1, CCS.Attached)    -- 最终状态为Attached.SRC
            baselib.report(0x00, "CVS 转换到 Attached.SRC 状态")
            baselib.delay(5)
            -- 3.b.iii: Skip to step 5  跳至步骤5, 这里执行 break 直接跳出循环到步骤5
            break
        end

        -- 第四步: CVS transitions to Unattached.SRC for (dcSRC.DRP x tDRP)
        hold_time = math.floor(tDRP * dcSRC)
        busilib.setUsbCcs(1, CCS.Unattached)
        busilib.setUsbRole(1, ROLE.Source)
        baselib.delay(hold_time)
        -- 4.a: CVS monitors CCs for Rd 监控CC引脚是否出现Rd（电压0.25V-2.04V）
        VCC1 = busilib.GetADC(ADC.CC1, 4)
        if VCC1 >= 250 and VCC1 <= 2040 then
            busilib.setUsbCcs(1, CCS.AttachWait)
            baselib.report(0x00, "检测到 CC 引脚的 Rd.CVS 转换到 AttachedWait.SRC.")
        end
        -- 4.b: If Rd is present for longer than tCCDebounce, CVS transitions to Attached.SRC. Continue to step 5  若Rd持续超过tCCDebounce（100-200ms）, 转换到Attached.SRC
        local cc1_rd_maintained = busilib.waitCondition4ad(ADC.CC1, 4, 250, 2040, 5, 250)  -- tCCDebounce = 200ms, 设置超时时间为250ms
        if cc1_rd_maintained == LuaOk then  -- Rd持续超过tCCDebounce，执行后续操作
            busilib.setUsbCcs(1, CCS.Attached)
            baselib.report(0x00, "Rd is present for longer than tCCDebounce.CVS Transition to Attached.SRC.")
            break  -- 跳出循环，继续到步骤5
        end
        attempt_count = attempt_count + 1 
    end

    -- 第五步: CVS verifies PUT transitions to Attached.SNK
    local trans1 = busilib.newTrans4ad(4, ADC.CC2, {2750})
    local monitor3 = busilib.newMonitor(TMD.CHECK_POINT, trans1, {1}, {0}, {0})  -- 此处为5.e步做准备
    -- 第5.a步: If PUT supports USB PD: PUT stabilizes VBUS before initiating USB PD communications [TD.4.7.2.V.2]  这里先检测VBUS如果在5V +- 5%以内就PASS
    if USB_PD_Support then
        local VBus = busilib.GetADC(ADC.VBUS, 4)  -- 获取VBUS电压
        if VBus >= 4750 and VBus <= 5250 then
            baselib.report(0x00, "TD.4.7.2.V.2 pass.")
        else
            baselib.report(0x00, "TD.4.7.2.V.2 fail.")
        end
    end

    -- 第5.b步: PUT sinks current according to CVS advertisement [TD.4.7.2.V.4]  
    -- 在500ms内监测VBUS电流, 电流数值可以是20ms内的平均值, 判别不超过500mA(对应tester宣传的500mA供电能力), 电流监控结果作为TD.4.7.2.V.4检查点进行上报。
    if busilib.waitCondition4ad(ADC.VBUS_I, 20, 500, 5000, 1, 500) == LuaOk then
        baselib.report(0x00, "步骤5.b: VBUS_I出现超过tester宣传的500mA供电能力的电流, TD.4.7.2.V.4 fail.")     --出现 LuaOK 说明有大于500mA的电流出现了一次,检查点fail
    else
        baselib.report(0x00, "步骤5.b: VBUS_I没有出现超过tester宣传的500mA供电能力的电流, TD.4.7.2.V.4 pass.")
    end

    -- 第5.c步: If PUT supports USB 3.1: PUT starts data communications on its SuperSpeed pairs [TD.4.7.2.V.5]
    -- 默认不支持USB 3.1, 所以不需要执行这一步

    -- 第5.d步: Else if PUT supports USB 2.0: PUT starts data communications on its D+/D- pair. [TD.4.7.2.V.6]
    -- 这一步还写不了，等赵工完成

    -- 第5.e步: 对于PUT_R, 检查CC2电压不超过2.75V, 将测量结果上报为TD.4.7.2.V.7    (原文:For a PUT_R, VCONN is not applied [TD.4.7.2.V.7] )
    if Captive_Cable then
        if busilib.getMonitorResult(monitor3) ~= 1 then   -- 出现1就是超过2750mV, 否则检查点pass
            baselib.report(0x00, "步骤5.e: PUT为PUT_R, 检测到CC2电压没有超过2750mV, TD.4.7.2.V.7 pass.")
        else
            baselib.report(0x00, "步骤5.e: PUT为PUT_R, 检测到CC2电压超过2750mV, TD.4.7.2.V.7 fail.")
        end
    end
    busilib.deleteMonitor(monitor3)   -- 删除监控器
    busilib.deleteTrans(trans1)
 
    if USB_PD_Support then
        -- 第六步: CVS transmits Discover ID PD messaging for 200ms    CVS发送Discover ID PD消息，持续200ms
        -- 清空未处理 PD 消息
        while tcpclib.PDRxCnt(1, 0) ~= 0 do
            local message, time = tcpclib.PDRxMsg(1, 0)
            baselib.report(0x00, "Unsolved PD message: " .. to_hex(message) .. " at " .. math.floor(time/1000) .. "ms.")
        end
        -- 发送 Discover ID 消息给 SOP
        ret = tcpclib.SendPD(1, 2, 0, 0,
            string.char(0x6F, 0x15, 0x01, 0x80, 0x00, 0xFF),
            2, 1000, 1000)   
        -- 判断是否发送成功，并等待 SOP 回复 ACK
        if ret == LuaOk then
            baselib.report(0x00, "Discover ID message sent successfully.")
            baselib.report(0x00, "TD.4.7.2.V.8 pass.")
            local wait_cnt = 0
            while tcpclib.PDRxCnt(1, 0) == 0 do
                baselib.delay(5)
                wait_cnt = wait_cnt + 1
                if wait_cnt >= 200 then
                    baselib.report(0x00, "DID ACK message Rx timeout, The test was forced to terminate!")
                    goto PD_END
                end
            end
        else
            baselib.report(0x00, "PD message send failed: error " .. ret .. ".")
            baselib.report(0x00, "TD.4.7.2.V.8 fail.")
            goto PD_END
        end
        -- 判断 SOP 回复 ACK
        while tcpclib.PDRxCnt(1, 0) ~= 0 do
            local message, time = tcpclib.PDRxMsg(1, 0)
            baselib.report(0x00, "Received PD message: " .. to_hex(message) .. " at " .. math.floor(time/1000) .. "ms.")
            if (message:byte(1) & 0x0F) == 0x0F         -- Vendor Defined Message
                and (message:byte(2) & 0x70) >= 0x10    -- Number of Data Objects >= 1
                and (message:byte(4) & 0x80) == 0x80    -- Structured VDM
                and (message:byte(3) & 0xDF) == 0x41    -- Discover Identity ACK
            then   
                baselib.report(0x00, "Received DID ACK message, the test was successfully ended!")
                baselib.report(0x00, "TD.4.7.2.V.9 pass.")
            end
        end 
    end

    :: PD_END ::
    -- 7.b步: PUT Remains in Attached.SNK during and for 500ms after step 6, 验证Attached.SNK维持500ms [TD.4.7.2.V.10]
    local monitor1 = busilib.newMonitor(TMD.TIME_LIST, 0, {1}, {500000}, {0})
    local monitor1result = busilib.waitMonitor(monitor1, 600)  
    if monitor1result ~= 1 then
        local VCC1 = busilib.GetADC(ADC.CC1, 8)
        baselib.report(0x00, "TD.4.7.2.V.10 fail, CC1 is " .. VCC1 .. "mV.")
    else
        baselib.report(0x00, "The PUT remains in the Attached state for more than 500ms.")
        baselib.report(0x00, "TD.4.7.2.V.10 pass.")
    end
    busilib.deleteMonitor(monitor1)

    -- 第八步: CVS programs Vbus source to meet 3.7V at the PUT connector   CVS将VBUS电压设置为3.7V
    busilib.preparePower(1, 1, 3700)   
    baselib.report(0x00, "CVS 已将 VBus 电压设置为3.7V.")

    -- 第九步: CVS verifies PUT remains in Attached.SNK
    -- 9.a: PUT maintains Rd on its CC [TD.4.7.2.V.11]
    local VCC1 = busilib.GetADC(ADC.CC1, 4)
    if VCC1 >= 250 and VCC1 <= 2040 then
        baselib.report(0x00, "TD.4.7.2.V.11 pass.")
    else
        baselib.report(0x00, "TD.4.7.2.V.11 fail.")
    end
    -- 9.b: For a PUT that supports USB 3.2 or USB 2.0 signaling, the data signaling is maintained. [TD.4.7.2.V.12]
    -- 这一步赵工正在弄

    -- 第十步: CVS removes Rps. CVS USB 2.0 and USB 3.1 signaling behaves as though it is in Attached.SRC as long as PUT is in Attached.SNK
    busilib.SetSwitchState(SW.CC1_RP_0A5, 0)  -- 断开CC1的Rp
    -- 后半句应该还写不了

    --[[ 第十一步: CVS decreases Vbus voltage by 0.1V  a: Wait 100ms  b: If PUT removes Rd or Vbus source voltage is below 800mV, continue to step 12
    c: CVS verifies PUT maintained Attached.SNK   i. PUT maintains Rd on its CC [TD.4.7.2.V.13]  ii. For a PUT that supports USB 3.2 or USB 2.0 signaling, the data signaling is maintained [TD.4.7.2.V.14]
    iii. PUT does not source Vbus [TD.4.7.2.V.15]    d. Continue to step 11 ]]
    baselib.report(0x00, "CVS 开始降低 VBus 输出.")
    local VBusValue = 3700
    while true do
        VBusValue = VBusValue - 100 
        busilib.preparePower(1, 1, VBusValue)  
        baselib.delay(100)
        local VBUS = busilib.GetADC(ADC.VBUS, 4) 
        if VBUS < 800 then    -- 如果VBUS电压低于800mV，直接跳出循环
            baselib.report(0x00, "CVS VBus 电压降低到 " .. VBusValue .. "mV.结束第十一步")
            break
        end
        VCC1 = busilib.GetADC(ADC.CC1, 4)
        -- 这里把b和c合并判断
        if VCC1 < 250 then    -- 这里需要专业人士来判断到底电压应该是多少
            baselib.report(0x00, "PUT maintains Rd on its CC, TD.4.7.2.V.13 pass.")
            -- c.ii步: For a PUT that supports USB 3.2 or USB 2.0 signaling, the data signaling is maintained [TD.4.7.2.V.14]
            -- 还写不了
            -- c.iii步: PUT does not source Vbus [TD.4.7.2.V.15]
            local result, vbus = cstmlib.VBusVerified(1)
            if result == 1 then
                baselib.report(0x00, "检测到 PUT 加载了 VBus, TD.4.7.2.V.15 fail.")
            else
                baselib.report(0x00, "PUT 没有加载 VBus, TD.4.7.2.V.15 pass.")
            end
        else
            baselib.report(0x00, "PUT removes Rd, TD.4.7.2.V.13 fail.")
            break
        end    
    end

    -- 第十二步: CVS applies Rd
    busilib.SetSwitchState(SW.CC1_RD, 1)
    baselib.report(0x00, "CVS 在 CC1 上加载 Rd.")

    -- 第十三步: CVS verifies PUT transitions to AttachWait.SRC within tOnePortToggleConnect, 验证PUT在tOnePortToggleConnect（0到80ms）转换到AttachWait.SRC [TD.4.7.2.V.16]
    baselib.delay(80)
    -- 第13.a步: PUT applies and maintains Rp. [TD.4.7.2.V.16] For a PUT_R, Rp is applied on both CCs
    VCC1 = busilib.GetADC(ADC.CC1, 4) 
    local VCC2 = busilib.GetADC(ADC.CC2, 4)
    if Captive_Cable then
        if VCC1 > 250 and VCC2 > 250 then
            baselib.report(0x00, "PUT是PUT_R, PUT 在两个CC端口提供了 Rp, TD.4.7.2.V.16 pass.")
        else
            baselib.report(0x00, "PUT是PUT_R, 有CC端口没提供 Rp, TD.4.7.2.V.16 fail.")
        end
    else
        if VCC1 > 250 then
            baselib.report(0x00, "PUT 在 CC1 加载了Rp, TD4.7.2.V.16 pass.")
        else
            baselib.report(0x00, "PUT 没有在 CC1 加载Rp, TD4.7.2.V.16 fail.")
        end
    end
    -- 第13.b步: PUT does not source Vbus [TD.4.7.2.V.17]
    local result, vbus = cstmlib.VBusVerified(1)
    if result == 1 then
        baselib.report(0x00, "检测到 PUT 加载了 VBus, TD.4.7.2.V.17 fail.")
    else
        baselib.report(0x00, "PUT 没有加载 VBus, TD.4.7.2.V.17 pass.")
    end
    -- 第13.c步: All data signaling ceases [TD.4.7.2.V.18]
    -- 这一步应该还写不了
    
    -- 第十四步: If Vbus is at or below 800 mV, continue to step 16
    local VBUS = busilib.GetADC(ADC.VBUS, 4)
    if VBUS > 800 then
        -- 第十五步: CVS verifies PUT remains in AttachWait.SRC for 500ms [TD.4.7.2.V.19]
        local AttachedWait_maintained = busilib.waitCondition4ad(ADC.CC1, 4, 250, 5000, 5, 500) 
        if AttachedWait_maintained == LuaOk then  -- Rp持续超过 500ms，判断 PUT 仍然处于 AttachWait.SRC
            baselib.report(0x00, "TD.4.7.2.V.19 pass.")
        end
    end
    
    -- 第十六步: CVS removes Vbus source

    -- 第十七步: CVS verifies that PUT transitions to Try.SNK: a. PUT applies Rd [TD.4.7.2.V.20], 通过验证PUT是否加载了 Rd 来确认PUT是否转换到 Try.SNK 
    VCC1 = busilib.GetADC(ADC.CC1, 4)
    if VCC1 < 150 then
        baselib.report(0x00, "TD.4.7.2.V.20 pass.")
    else
        baselib.report(0x00, "TD.4.7.2.V.20 fail.")
    end

    -- 第十八步: CVS transitions to Disabled , CVS最终状态恢复为Disabled
    busilib.setUsbCcs(1, CCS.Disabled)
end

:: Script_END ::
baselib.report(0x00, "TD4.7.2 completed.")
baselib.report(0x07, "\x04")  -- 结束标记
